//
// Created by Administrator on 2020/1/6.
//

#include <unistd.h>
#include <cstdlib>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include "shell.h"
#include "../include/log_utils.h"
#include "../utils/string_utils.h"
#include "shell_utils.h"

int read_from_socket(int socket_fd,std::string &result){
    result.clear();
    char buffer[1]={0};
    int read_length=0;
    printf("[!] before enter read loop\n");
    while (read(socket_fd,buffer,1)==1){
        result.append(buffer);
        read_length++;
    }
    printf("[+] read gotten string:%s(%d)\n",result.c_str(),read_length);
    return read_length;
}

int main(int argc,char* argv[]){
    printf("interactive shell at pid:%d uid:%d\n",getpid(),getuid());
    if(argc<2){
        printf("[!] usage:shell [port]\n");
        return -1;
    }
    int port=atoi(argv[1]);
    printf("[!] attempt to create socket on port:%d\n",port);
    int socket_fd=socket(AF_INET,SOCK_STREAM | SOCK_CLOEXEC,0);
    if(socket_fd<0){
        printf("[!] fail to create socket fd\n");
        return -1;
    }
    socklen_t sock_addr_size=sizeof(struct sockaddr_in);
    struct sockaddr_in s_add;
    bzero(&s_add,sock_addr_size);
    s_add.sin_family=AF_INET;
    s_add.sin_addr.s_addr=htonl(INADDR_ANY);
    s_add.sin_port=htons(port);

    int bind_ret=bind(socket_fd,(struct sockaddr *)(&s_add),sock_addr_size/*ought to be sizeof(sockaddr)*/);
    if(bind_ret<0){
        printf("[!] fail to bind to port:%d\n",port);
        return -1;
    }
    int listen_ret= listen(socket_fd,5);
    if(listen_ret<0){
        printf("[-] fail to listen\n");
        return -1;
    }
    printf("[!] socket start to accept\n");
    struct sockaddr_in c_add;
    int client_fd=accept(socket_fd, (struct sockaddr *)(&c_add), &sock_addr_size);
    printf("[+] accepted client_fd:%d\n",client_fd);
    std::string server_hello="server hello";
    send(client_fd,server_hello.c_str(),server_hello.size(),0);
    printf("[+] sever hello sent\n");
    FILE* client_fp=fdopen(client_fd,"rw");
    if(!client_fp){
        printf("[-] fail to fdopen client_fd\n");
        return -1;
    }
    printf("[+] client_fp:%p\n",client_fp);
    //添加读取socket并处理命令的代码
    std::string msg;
    std::string result;
    while(true){
        read_from_file(client_fp,msg);
        if(msg.empty())
            continue;
        if(msg=="exit"){
            printf("[!] exit command received\n");
            break;
        }
        printf("[!] attempt to execute command:%s\n",msg.c_str());
        int cmd_ret= shell_with_return(msg,result);
        printf("[+] command executed with result:%d and result has been written\n",cmd_ret);
        break;
    }
    //退出提示
    printf("[!] interactive shell on pid:%d will exit\n",getpid());
    return 0;
}
